package kvsrv

import (
	"fmt"
	"log"
	"sync"
)

const Debug = false

func DPrintf(format string, a ...interface{}) (n int, err error) {
	if Debug {
		log.Printf(format, a...)
	}
	return
}

type KVServer struct {
	mu sync.Mutex

	// Your definitions here.
	kvList     []keyAndValue
	MessageMap sync.Map
}

type keyAndValue struct {
	key   string
	value string
}

// Get(key) fetches the current value for the key
// A Get for a non-existent key should return an empty string
func (kv *KVServer) Get(args *GetArgs, reply *GetReply) {
	// fmt.Println("Get method: ", "Wanted Key is", args.Key)

	// Your code here.
	key := args.Key
	kv.mu.Lock()
	// kv.seeKV()

	for _, val := range kv.kvList {
		if val.key == key {
			reply.Value = val.value
			break
		} else {
			reply.Value = ""
		}
	}
	// fmt.Println("Get method: the server KV are ", kv.kvList, "   returned value is ", reply.Value)
	kv.mu.Unlock()
}

// Put(key, value) installs or replaces the value for a particular key in the map
func (kv *KVServer) Put(args *PutAppendArgs, reply *PutAppendReply) {
	// fmt.Println("Put method: ", "Key is", args.Key, " Value is", args.Value)
	// Your code here.
	pKey := args.Key
	pValue := args.Value

	kv.mu.Lock()
	// kv.seeKV()

	flag := false
	for i := range kv.kvList {
		val := &kv.kvList[i]
		if val.key == pKey {
			val.value = pValue
			flag = true
		}
	}
	if !flag {
		kAV := keyAndValue{
			key:   pKey,
			value: pValue,
		}
		kv.kvList = append(kv.kvList, kAV)
	}
	// fmt.Println("Put method: the server KV are ", kv.kvList, "   returned value is ", reply.Value)
	kv.mu.Unlock()
}

// Append(key, arg) appends arg to key's value and returns the old value
// An Append to a non-existent key should act as if the existing value were a zero-length string
func (kv *KVServer) Append(args *PutAppendArgs, reply *PutAppendReply) {
	// fmt.Println("Append method: ", "Key is", args.Key, " Value is", args.Value)
	// Your code here.
	// Your code here.
	pKey := args.Key
	pValue := args.Value
	pId := args.MessageId
	pType := args.MessageType

	if pType == "add" {
		value, ok := kv.MessageMap.Load(pId)
		if ok {
			reply.Value = value.(string)
			return
		}
	} else {
		kv.MessageMap.Delete(pId)
		return
	}
	kv.mu.Lock()
	// kv.seeKV()

	flag := false

	for i := range kv.kvList {
		val := &kv.kvList[i]
		if val.key == pKey {
			reply.Value = val.value

			// fmt.Println("In Append method: ", "Key is", pKey, " Value is", pValue)
			// fmt.Println("len(val.value):", len(val.value))
			if len(val.value) == 0 {
				// fmt.Println("change the val.value")
				// fmt.Println("before val.value:", val.value)
				val.value = pValue
				// fmt.Println("after val.value:", val.value)
			} else {
				// fmt.Println("add the val.value")
				// fmt.Println("before val.value:", val.value)
				val.value += pValue
				// fmt.Println("after val.value:", val.value)
			}

			flag = true
			break
		}
	}
	if !flag {
		kAV := keyAndValue{
			key:   pKey,
			value: pValue,
		}
		kv.kvList = append(kv.kvList, kAV)
	}
	// fmt.Println("Append method: the server KV are ", kv.kvList, "   returned value is ", reply.Value)
	kv.mu.Unlock()
	if flag {
		kv.MessageMap.Store(pId, reply.Value)
	}
}

func StartKVServer() *KVServer {
	kv := new(KVServer)

	// You may need initialization code here.
	kv.kvList = []keyAndValue{}

	return kv
}

func (kv *KVServer) seeKV() {
	fmt.Println("the kv .....")
	for _, val := range kv.kvList {
		fmt.Println("key:", val.key, " val: ", val.value)
	}

}
